/*
 * Copyright © OpenAtom Foundation.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *     http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

package io.iec.edp.caf.databaseobject.common.database;

import java.math.BigDecimal;
import java.sql.*;

/**
 * @author liu_wei
 */
public abstract class AbstractDatabaseImpl implements GspDatabase {

    private Connection dbConn;
    private DbConfigData dbConfig;
    private Statement statement = null;

    public AbstractDatabaseImpl(DbConfigData configData) {
        this.dbConfig = configData;
    }

    /**
     * 获取根据数据库连接信息对应的数据访问对象
     *
     * @param dbConfiguration 连接信息
     * @return 连接对象
     */
    public static GspDatabase getDatabase(DbConfigData dbConfiguration) {
        return GspDbFactory.getDatabase(dbConfiguration);
    }

    /**
     * 获取Connection
     *
     * @param configData 数据库参数
     * @return JDBC Connection
     * @throws SQLException 异常
     */
    public abstract Connection getConnection(DbConfigData configData) throws SQLException;

    @Override
    public void open() {
        //每次open之前，关闭之前遗留的statement。这个修改是为了解决查询ResultSet不能随时关闭的方法
        try {
            if (statement != null) {
                statement.close();
            }
        } catch (SQLException e) {
            throw new RuntimeException("关闭Statement出错：" + e);
        }

        if (dbConn == null) {
            boolean connectSuccess = false;
            int count = 0;
            while (!connectSuccess) {
                count++;
                try {
                    dbConn = this.getConnection(dbConfig);
                    connectSuccess = true;
                } catch (Exception e) {
                    if (count >= 5) {
                        throw new RuntimeException("获取数据库Connection出错：", e);
                    }
                }
            }
        }
    }

    @Override
    public void close() {
        if (dbConn != null) {
            try {
                dbConn.close();
                dbConn = null;
            } catch (SQLException e) {
                throw new RuntimeException("关闭Connection出错：", e);
            }
        }
    }

    @Override
    public int execSqlStatement(String sqlStatement) throws SQLException {

        int result = 0;
        try {
            this.open();
            statement = dbConn.createStatement();
            //设置超时时间
            statement.setQueryTimeout(dbConfig.getCommandTimeout() == 0 ? dbConfig.getDefaultcommandtimeout() : dbConfig.getDefaultcommandtimeout());
            result = statement.executeUpdate(sqlStatement);

        } catch (SQLException e) {
            throw new RuntimeException("sql执行出错：", e);
        } finally {
            this.close();
        }
        this.close();
        return result;
    }

    @Override
    public void execSqlStatement(String[] sqlStatements) throws SQLException {

        try {
            this.open();
            statement = dbConn.createStatement();
            //设置超时时间
            statement.setQueryTimeout(dbConfig.getCommandTimeout() == 0 ? dbConfig.getDefaultcommandtimeout() : dbConfig.getDefaultcommandtimeout());
            for (String sql : sqlStatements) {
                statement.executeUpdate(sql);
            }
        } catch (SQLException e) {
            throw new RuntimeException("sql执行出错：" + e);
        } finally {
            this.close();
        }
    }

    @Override
    public ResultSet executeResultSet(String sqlStatement) throws SQLException {

        ResultSet result = null;
        try {
            this.open();
            statement = dbConn.createStatement();
            //设置超时时间
            statement.setQueryTimeout(dbConfig.getCommandTimeout() == 0 ? dbConfig.getDefaultcommandtimeout() : dbConfig.getDefaultcommandtimeout());
            result = statement.executeQuery(sqlStatement);

        } catch (SQLException e) {
            throw new RuntimeException("sql执行出错：" + sqlStatement, e);
        }
        return result;
    }

    @Override
    public void execSqlStatement(String sqlStatement, Object[][] paramDataList) throws SQLException {
        PreparedStatement prepStatement = null;
        try {
            this.open();
            prepStatement = dbConn.prepareStatement(sqlStatement);
            //设置超时时间
            prepStatement.setQueryTimeout(dbConfig.getCommandTimeout() == 0 ? dbConfig.getDefaultcommandtimeout() : dbConfig.getDefaultcommandtimeout());
            for (Object[] objects : paramDataList) {
                for (int j = 0; j < objects.length; j++) {
                    if (objects[j] instanceof Integer) {
                        prepStatement.setInt(j + 1, (Integer) objects[j]);
                    } else if (objects[j] instanceof String) {
                        prepStatement.setString(j + 1, (String) objects[j]);
                    } else if (objects[j] instanceof Double) {
                        prepStatement.setDouble(j + 1, (Double) objects[j]);
                    } else if (objects[j] instanceof BigDecimal) {
                        prepStatement.setBigDecimal(j + 1, (BigDecimal) objects[j]);
                    } else if (objects[j] instanceof Float) {
                        prepStatement.setFloat(j + 1, (Float) objects[j]);
                    } else if (objects[j] instanceof Long) {
                        prepStatement.setLong(j + 1, (Long) objects[j]);
                    } else if (objects[j] instanceof Boolean) {
                        prepStatement.setBoolean(j + 1, (Boolean) objects[j]);
                    } else if (objects[j] instanceof Date) {
                        prepStatement.setDate(j + 1, (Date) objects[j]);
                    } else if (objects[j] instanceof Timestamp) {
                        prepStatement.setTimestamp(j + 1, (Timestamp) objects[j]);
                    } else {
                        prepStatement.setObject(j + 1, objects[j]);
                    }
                }
                prepStatement.addBatch();
            }
            prepStatement.executeBatch();

        } catch (SQLException e) {
            throw new RuntimeException("sql执行出错：" + e);
        } finally {
            try {
                if (prepStatement != null) {
                    prepStatement.clearBatch();
                    prepStatement.close();
                }
            } catch (SQLException e) {
                throw new RuntimeException("关闭prepStatement出错：" + e);
            }
            this.close();
        }
    }

    @Override
    public void execSqlStatementNotAutomatic(String sqlStatement) throws SQLException {
        try {
            statement = dbConn.createStatement();
            //设置超时时间
            statement.setQueryTimeout(dbConfig.getCommandTimeout() == 0 ? dbConfig.getDefaultcommandtimeout() : dbConfig.getDefaultcommandtimeout());
            statement.executeUpdate(sqlStatement);
        } catch (SQLException e) {
            throw new RuntimeException("sql执行出错：" + e);
        } finally {
            if (statement != null) {
                statement.close();
            }
        }
    }
}
